package com.itaq.cheetah.serviceA.config.exception.advice;

import cn.hutool.http.HttpStatus;
import com.itaq.cheetah.serviceA.config.enums.SystemCodeEnum;
import com.itaq.cheetah.serviceA.config.exception.BaseException;
import com.itaq.cheetah.serviceA.config.exception.CustomException;
import com.itaq.cheetah.serviceA.config.exception.UnauthorizedException;
import com.itaq.cheetah.serviceA.model.result.WrapperResult;
import com.itaq.cheetah.serviceA.utils.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.AccessDeniedException;
import java.security.SignatureException;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author cheetah
 * @date 2021/10/20
 */
@RestControllerAdvice
@Slf4j
public class ValidationAdvice {

    @ExceptionHandler(value = AccessDeniedException.class)
    @ResponseBody
    public WrapperResult<Map<String, Object>> unauthorizedErrorHandler(AccessDeniedException exception) {
        log.error("【UnauthorizedException】:", exception);
        return WrapperResult.<Map<String, Object>>builder().code(SystemCodeEnum.UNAUTHORIZED.code()).data(null).msg("无此接口的访问权限").build();
    }

    @ExceptionHandler(value = UnauthorizedException.class)
    @ResponseBody
    public WrapperResult<Map<String, Object>> unauthorizedErrorHandler(UnauthorizedException exception) {
        log.error("【UnauthorizedException】:{}", exception.getMessage());
        return WrapperResult.<Map<String, Object>>builder().code(SystemCodeEnum.UNAUTHORIZED.code()).data(null).msg("未授权的访问").build();
    }

    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public WrapperResult customException(CustomException e) {
        //获取异常信息,获取异常堆栈的完整异常信息
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        //日志输出异常详情
        log.error(sw.toString());
        WrapperResult wrapperResult = new WrapperResult();
        wrapperResult.setMsg(e.getMessage());
        wrapperResult.setCode(SystemCodeEnum.SUCCESS.code());
        return wrapperResult;
    }

    /**
     * 基础异常
     */
    @ExceptionHandler(BaseException.class)
    public WrapperResult baseException(BaseException e) {
        return WrapperResult.faild(e.getMessage());
    }


    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public void handler(ConstraintViolationException e) {
        StringBuffer errorMsg = new StringBuffer();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        violations.forEach(x -> errorMsg.append(x.getMessage()).append(";"));
        ServletUtils.renderString(HttpStatus.HTTP_INTERNAL_ERROR, WrapperResult.faild(errorMsg.toString()));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public void handler(MethodArgumentNotValidException e) {
        StringBuffer sb = new StringBuffer();
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        allErrors.forEach(msg -> sb.append(msg.getDefaultMessage()).append(";"));
        ServletUtils.renderString(HttpStatus.HTTP_INTERNAL_ERROR, WrapperResult.faild(sb.toString()));
    }

    @ExceptionHandler(SignatureException.class)
    @ResponseBody
    public WrapperResult handler(SignatureException e) {
        return WrapperResult.faild("验签失败");
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public WrapperResult handler(Exception e) {
        //获取异常信息,获取异常堆栈的完整异常信息
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        //日志输出异常详情
        log.error(sw.toString());
        return WrapperResult.faild("服务异常，请稍后再试");
    }
}
